# SqlTypeRegistry.java

    package org.codefilarete.stalactite.sql.ddl;

    import java.util.HashMap;
    import java.util.Map;

    import org.codefilarete.stalactite.sql.ddl.structure.Column;
    import org.codefilarete.stalactite.sql.statement.SQLStatement.BindingException;

    /**
     * A registry that let one specifies SQL types for Java types and {@link Column}s.
     * This is used for schema generation.
     * One can specify the SQL type of a particular {@link Column} with {@link #put(Column, String)}, as well as one for
     * a Java class with {@link #put(Class, String)}. The latter will act as a fallback if an SQL type is not found for a
     * {@link Column} : its {@link Column#getJavaType() Java type} will be checked for SQL type presence.
     * Designed as a wrapper of {@link JavaTypeToSqlTypeMapping} by adding {@link Column} type registration.
     *
     * See {@link org.codefilarete.stalactite.sql.statement.binder.ParameterBinderRegistry} for default readers and writers
     * to database.
     *
     * @author Guillaume Mary
     * @see #getTypeName(Column)
     */
    public class SqlTypeRegistry {

    	private final JavaTypeToSqlTypeMapping javaTypeToSqlType;

    	private final Map<Column, String> columnToSQLType = new HashMap<>();

    	public SqlTypeRegistry() {
    		this(new JavaTypeToSqlTypeMapping());
    	}

    	public SqlTypeRegistry(JavaTypeToSqlTypeMapping javaTypeToSqlTypeMapping) {
    		this.javaTypeToSqlType = javaTypeToSqlTypeMapping;
    	}

    	public JavaTypeToSqlTypeMapping getJavaTypeToSqlTypeMapping() {
    		return javaTypeToSqlType;
    	}

    	/**
    	 * Registers a Java class to a SQL type mapping
    	 *
    	 * @param clazz the Java class to bind
    	 * @param sqlType the SQL type to map on the Java type
    	 */
    	public void put(Class clazz, String sqlType) {
    		javaTypeToSqlType.put(clazz, sqlType);
    	}

    	/**
    	 * Register a Java class to a SQL type mapping
    	 *
    	 * @param clazz the Java class to bind
    	 * @param sqlType the SQL type to map on the Java type
    	 * @param size the minimal size from which the SQL type will be used
    	 */
    	public void put(Class clazz, String sqlType, Size size) {
    		javaTypeToSqlType.put(clazz, sqlType, size);
    	}

    	/**
    	 * Register a column to a SQL type mapping
    	 *
    	 * @param column the column to bind
    	 * @param sqlType the SQL type to map on the Java type
    	 */
    	public void put(Column column, String sqlType) {
    		columnToSQLType.put(column, sqlType);
    	}

    	/**
    	 * Gives the SQL type name of a column. Main entry point of this class.
    	 *
    	 * @param column a column
    	 * @return the SQL type for the given column
    	 */
    	public String getTypeName(Column column) {
    		// first, very fine-grained tuning
    		String typeName = columnToSQLType.get(column);
    		if (typeName != null) {
    			return typeName;
    		}
    		// then, tuning by Java type : same types may use same SQL type (id, timestamp, ...)
    		Class javaType = column.getJavaType();
    		Size size = column.getSize();
    		if (size != null) {
    			return javaTypeToSqlType.getTypeName(javaType, size);
    		} else {
    			try {
    				return javaTypeToSqlType.getTypeName(javaType);
    			} catch (BindingException e) {
    				// Exception is wrapped for a more accurate message (column in message)
    				throw new BindingException("No sql type defined for column " + column.getAbsoluteName(), e);
    			}
    		}
    	}
    }